const _ = require('lodash')
const isRetryAllowed = require('is-retry-allowed')

const SAFE_HTTP_METHODS = ['get', 'head', 'options']


function isRetryableError(error) {
    if (_.indexOf(SAFE_HTTP_METHODS, error.config.method) < 0) {
        return false
    }

    if (error.response && error.response.status) {
        const status = error.response.status
        return (status == 429)
            || (status >= 500 && status < 600)
            || (status >= 100 && status < 200)
    }

    return isRetryableError(error)
}

module.exports = (axios) => {
    axios.interceptors.response.use(null, error => {
        const getRetryableConfig = () => {
            const retryable = _.get(error, 'config.retryable')
            if (_.isUndefined(retryable)) {
                return undefined
            }
            return _.assignWith(retryable, {
                retry: 0,
                retryAttempt: 1,
                shouldRetry: () => true,
                retryDelay: ()=>1000,
                onRetry: ()=>{},
            }, (to, from) => {
                return _.isUndefined(to) ? from: to
            })
        }

        const retryable = getRetryableConfig()
        if (_.isUndefined(retryable)) {
            return Promise.reject(error)
        }

        const {retry, retryAttempt, retryDelay, shouldRetry, onRetry} = retryable
        if (!shouldRetry(retryAttempt, error) || retryAttempt > retry) {
            return Promise.reject(error)
        }

        if (!isRetryableError(error)) {
            return Promise.reject(error)
        }

        return new Promise(resolve => {
            setTimeout(() => {
                onRetry(retryAttempt, error)
                retryable.retryAttempt += 1
                resolve(axios(error.config))
            }, retryDelay())
        })
    })

    return axios
}
